﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Windows.Threading;
using System.Threading;
using Vapor.Collections;

namespace GameControlTest
{
    public partial class GameControlHybrid : UserControl
    {
        private Thread _updateThread;
        private Thread _collisionThread;
        private List<GameObject> _gameObjects;
        private LocklessQueue<Point[]> _locationUpdates;
        private DateTime _lastTime;
        private int _xDir = 1;
        private int _yDir = 1;

        private static Random s_random = new Random();

        public GameControlHybrid()
        {
            InitializeComponent();

            _gameObjects = new List<GameObject>();
            _locationUpdates = new LocklessQueue<Point[]>();

            _lastTime = DateTime.Now;

            List<GameObject> collidables = new List<GameObject>();

            for (int i = 0; i < App.ObjectCount; i++)
            {
                GameObject go = new GameObject(new Rect(s_random.Next(800) - 400,
                    s_random.Next(600) - 300, App.RectSize, App.RectSize), Colors.Black);
                _gameObjects.Add(go);
                this.LayoutRoot.Children.Add(go.DrawRectangle);
            }

            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);

            this.KeyDown += new KeyEventHandler(GameControlHybrid_KeyDown);

            _updateThread = new Thread(Update);
            _updateThread.Start();

            _collisionThread = new Thread(CheckForCollisions);
            _collisionThread.Start();
        }

        private void GameControlHybrid_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Up)
            {
                _xDir *= -1;
                _gameObjects[0].Translate(0, -5);
            }
            if (e.Key == Key.Down)
            {
                _yDir *= -1;
                _gameObjects[0].Translate(0, 5);
            }
            if (e.Key == Key.Left)
            {
                _yDir *= -1;
                _gameObjects[0].Translate(-5, 0);
            }
            if (e.Key == Key.Right)
            {
                _yDir *= -1;
                _gameObjects[0].Translate(5, 0);
            }
        }

        private void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            DateTime now = DateTime.Now;
            TimeSpan elapsedTime = now - _lastTime;
            float elapsedTimeRatio = (float)elapsedTime.TotalSeconds / ((float)60 / 1000);
            _lastTime = now;

            Point[] locationUpdates;
            if(_locationUpdates.Dequeue(out locationUpdates))
            {
                for (int i = 0; i < locationUpdates.Length; i++)
                {
                    _gameObjects[i].Update(locationUpdates[i].X, locationUpdates[i].Y, elapsedTimeRatio);
                }
            }
            //CheckForCollisions();
        }

        private void Update()
        {
            while (true)
            {
                if (_locationUpdates.Count < 5)
                {
                    Point[] updatePoints = new Point[_gameObjects.Count];
                    for (int i = 0; i < updatePoints.Length; i++)
                    {
                        updatePoints[i] = new Point(_xDir, _yDir);
                    }
                    _locationUpdates.Enqueue(updatePoints);
                }
                else
                {
                    Thread.Sleep(1);
                }
            }
        }

        private void CheckForCollisions()
        {
            while (true)
            {
                List<GameObject> checkList = _gameObjects.OrderBy(x => x.CollisionRect.X).ToList();
                for (int i = 0; i < checkList.Count; i++)
                {
                    GameObject a = checkList[i];
                    for (int j = i + 1; j < checkList.Count && checkList[j].CollisionRect.Left < a.CollisionRect.Right; j++)
                    {
                        GameObject b = checkList[j];
                        Rect tempRect = a.CollisionRect;
                        tempRect.Intersect(b.CollisionRect);
                        if (!tempRect.IsEmpty)
                        {
                            a.Collided(b);
                            b.Collided(a);
                        }
                    }
                }
            }
        }
    }
}
